package com.xsy.glsurfaceview

import android.graphics.Bitmap
import android.graphics.PointF
import android.opengl.GLES30
import android.opengl.GLUtils
import android.opengl.Matrix
import android.util.Log
import com.xsy.glsurfaceview.utils.ShaderUtils
import java.nio.ByteBuffer
import java.nio.ByteOrder


class TextureRenderBigEye(bitmap: Bitmap,vertexShaderCode: String, fragmentShaderCode: String) {
    companion object {
        const val vertex_file_path = "vshader/BigEye.glsl"
        const val fragment_file_path = "fshader/BigEye.glsl"
    }

    private val coordData = floatArrayOf(
        //顶点坐标           纹理坐标
        -1.0f, 1.0f, 0.0f, 0.0f, 0.0f,  //左上角
        -1.0f, -1.0f, 0.0f, 0.0f, 1.0f, //左下角
        1.0f, 1.0f, 0.0f, 1.0f, 0.0f,   //右上角
        1.0f, -1.0f, 0.0f, 1.0f, 1.0f   //右下角
    )


    private var translateMatrix = FloatArray(16)

    private var mProgram = -1
    private var mPositionHandle = -1
    private var mTexCoordHandle = -1
    private var mMVPTMatrixHandle = -1
    private var mSamplerHandle = -1

    private var mTextureId = -1

    private var mCenterLeftEyeHandle = -1
    private var mCenterRightEyeHandle = -1

    private var mBeginLeftEyeHandle = -1
    private var mEndLeftEyeHandle = -1
    private var mBeginRightEyeHandle = -1
    private var mEndRightEyeHandle = -1

    private var mImageSizeHandle = -1
    private var mFaceInfo: FaceInfo? = null
    private var mImageWidth = -1
    private var mImageHeight = -1

    private val vboId: IntArray = IntArray(1)

    init {
        mTextureId = uploadTexture(bitmap)
        mImageWidth = bitmap.width
        mImageHeight = bitmap.height

        val bb = ByteBuffer.allocateDirect((coordData.size * 4))
        bb.order(ByteOrder.nativeOrder())
        val coordBuffer = bb.asFloatBuffer()
        coordBuffer.put(coordData)
        coordBuffer.position(0)
        mProgram = ShaderUtils.createGLProgram(vertexShaderCode, fragmentShaderCode)
        GLES30.glGenBuffers(1, vboId, 0)
        GLES30.glBindBuffer(GLES30.GL_ARRAY_BUFFER, vboId[0])
        GLES30.glBufferData(
            GLES30.GL_ARRAY_BUFFER, bb.capacity(),
            bb, GLES30.GL_STATIC_DRAW
        )
        Matrix.setIdentityM(translateMatrix, 0)
        mPositionHandle = GLES30.glGetAttribLocation(mProgram, "aPosition")
        GLES30.glEnableVertexAttribArray(mPositionHandle)
        checkGlError("aPosition")
        mTexCoordHandle = GLES30.glGetAttribLocation(mProgram, "aTexCoord")
        GLES30.glEnableVertexAttribArray(mTexCoordHandle)
        checkGlError("aTexCoord")
        mMVPTMatrixHandle = GLES30.glGetUniformLocation(mProgram, "uMVPTMatrix")

        checkGlError("uTMatrix")
        mSamplerHandle = GLES30.glGetUniformLocation(mProgram, "uSampler")
        checkGlError("uSampler")

        mCenterLeftEyeHandle = GLES30.glGetUniformLocation(mProgram, "uCenterLeftEye")
        mCenterRightEyeHandle = GLES30.glGetUniformLocation(mProgram, "uCenterRightEye")

        mBeginLeftEyeHandle = GLES30.glGetUniformLocation(mProgram, "uBeginLeftEye")
        mEndLeftEyeHandle = GLES30.glGetUniformLocation(mProgram, "uEndLeftEye")
        mBeginRightEyeHandle = GLES30.glGetUniformLocation(mProgram, "uBeginRightEye")
        mEndRightEyeHandle = GLES30.glGetUniformLocation(mProgram, "uEndRightEye")

        mImageSizeHandle = GLES30.glGetUniformLocation(mProgram, "uImageSize")

        GLES30.glBindBuffer(GLES30.GL_ARRAY_BUFFER, 0)
    }


    private fun transData(handle: Int, point: PointF){
        val floatArray = floatArrayOf(point.x, point.y)
        val floatBuffer = ByteBuffer.allocateDirect(2*4).order(ByteOrder.nativeOrder()).asFloatBuffer()
        floatBuffer.put(floatArray)
        floatBuffer.position(0)

        GLES30.glUniform2fv(handle, 1, floatBuffer)
    }

    fun setFaceInfo(faceInfo: FaceInfo){
        mFaceInfo = faceInfo
    }

    fun draw(mvpMatrix: FloatArray) {
        //使用program
        GLES30.glUseProgram(mProgram)
        GLES30.glBindBuffer(GLES30.GL_ARRAY_BUFFER, vboId[0])

        GLES30.glVertexAttribPointer(
            mPositionHandle,
            3,
            GLES30.GL_FLOAT,
            false,
            5 * Float.SIZE_BYTES,
            0
        )
        checkGlError("mPositionHandle")

        GLES30.glVertexAttribPointer(
            mTexCoordHandle,
            2,
            GLES30.GL_FLOAT,
            false,
            5 * Float.SIZE_BYTES,
            3 * Float.SIZE_BYTES
        )
        checkGlError("mTexCoordHandle")
        //传入正交矩阵修复变形
        GLES30.glUniformMatrix4fv(mMVPTMatrixHandle, 1, false, mvpMatrix, 0)
        checkGlError("mTMatrixHandle")

        GLES30.glActiveTexture(GLES30.GL_TEXTURE0)
        GLES30.glBindTexture(GLES30.GL_TEXTURE_2D, mTextureId)
        GLES30.glUniform1i(mSamplerHandle, 0)


        if(mFaceInfo != null) {

            transData(mCenterLeftEyeHandle, mFaceInfo!!.mCenterLeftEye)
            transData(mCenterRightEyeHandle, mFaceInfo!!.mCenterRightEye)
            transData(mBeginLeftEyeHandle, mFaceInfo!!.mBeginLeftEye)
            transData(mEndLeftEyeHandle, mFaceInfo!!.mEndLeftEye)
            transData(mBeginRightEyeHandle, mFaceInfo!!.mBeginRightEye)
            transData(mEndRightEyeHandle, mFaceInfo!!.mEndRightEye)


            transData(mImageSizeHandle, PointF(mImageWidth.toFloat(), mImageHeight.toFloat()))
        }

        //drawAarray, 绘制矩型
        GLES30.glDrawArrays(GLES30.GL_TRIANGLE_STRIP, 0, 4)

        // 解绑VBO
        GLES30.glBindBuffer(GLES30.GL_ARRAY_BUFFER, 0)
    }

    fun onDestroy() {
        GLES30.glDeleteProgram(mProgram)
        GLES30.glDeleteBuffers(1, vboId, 0)
    }


    private fun uploadTexture(bitmap: Bitmap): Int {

        val textureIds = IntArray(1)
        GLES30.glGenTextures(1, textureIds, 0)
        GLES30.glBindTexture(GLES30.GL_TEXTURE_2D, textureIds[0])

        GLES30.glTexParameteri(
            GLES30.GL_TEXTURE_2D,
            GLES30.GL_TEXTURE_MIN_FILTER,
            GLES30.GL_LINEAR
        )
        GLES30.glTexParameteri(
            GLES30.GL_TEXTURE_2D,
            GLES30.GL_TEXTURE_MAG_FILTER,
            GLES30.GL_LINEAR
        )

        GLUtils.texImage2D(
            GLES30.GL_TEXTURE_2D,
            0,
            GLES30.GL_RGBA,
            bitmap,
            0
        )
        bitmap.recycle()
        GLES30.glBindTexture(GLES30.GL_TEXTURE_2D, 0)
        return textureIds[0]
    }

    fun checkGlError(op: String) {
        val error = GLES30.glGetError();

        if (error != GLES30.GL_NO_ERROR) {
            val msg = op + ": glError 0x" + Integer.toHexString(error)
            Log.e("MyGLSurfaceView", msg)
        }
    }


}